/**
 * Copyright 2019-2022 Huawei Technologies Co., Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "infra/om/stats/ai_stats_log_builder.h"

#include <sstream>
#include <dlfcn.h>
#include <atomic>
#include <mutex>

#include "infra/base/assertion.h"

namespace hiai {
#ifdef __LP64__
static const char* libraryName = "/vendor/lib64/libai_client.so";
#else
static const char* libraryName = "/vendor/lib/libai_client.so";
#endif
namespace {
using RequestStatsFunc = void (*)(hiai::HIAI_Stats_Info);

static std::mutex g_mutex;
static void* g_handle = nullptr;
static RequestStatsFunc g_requestStatsFunc = nullptr;
Status Init()
{
    std::lock_guard<std::mutex> lock(g_mutex);
    if (g_requestStatsFunc != nullptr) {
        return SUCCESS;
    }
    g_handle = dlopen(libraryName, RTLD_LAZY);
    if (g_handle == nullptr) {
        STATS_LOGW("load lib failed,errmsg [%s]", dlerror());
        return FAILURE;
    }

    g_requestStatsFunc = reinterpret_cast<void (*)(HIAI_Stats_Info)>(dlsym(g_handle, "HIAI_Stats_RequestStats"));
    if (g_requestStatsFunc == nullptr) {
        STATS_LOGW("dlsym HIAI_Stats_RequestStats in lib[%s] failed,errmsg [%s]", libraryName, dlerror());
        dlclose(g_handle);
        g_handle = nullptr;
        return FAILURE;
    }
    return SUCCESS;
}
}

AiStatsLogBuilder& AiStatsLogBuilder::CallTimeNow()
{
    this->statsData_.callTime = AiStatsTime::TimeNow();
    return *this;
}

AiStatsLogBuilder& AiStatsLogBuilder::RunTime()
{
    this->statsData_.runTime = this->time_.GetRunTime();
    return *this;
}

AiStatsLogBuilder& AiStatsLogBuilder::StartStats(
    unsigned int uid, AiStatsEngineType engineType, const char* clientInterfaceName, const char* processName)
{
    if (Init() != SUCCESS) {
        return *this;
    }
    this->statsData_.engineType = engineType;
    this->statsData_.callPkg = static_cast<pid_t>(uid);
    this->statsData_.interfaceName = clientInterfaceName;
    this->statsData_.processName = processName;
    this->CallTimeNow();
    this->time_.StartProcess();
    return *this;
}

void AiStatsLogBuilder::EndStats(int result)
{
    HIAI_EXPECT_NOT_NULL_VOID(g_requestStatsFunc);
    this->time_.EndProcess();
    this->statsData_.runTime = this->time_.GetRunTime();
 
    HIAI_Stats_Info statsInfo {
        .uid = static_cast<uint32_t>(this->statsData_.callPkg),
        .engineType = this->statsData_.engineType,
        .interfaceName = this->statsData_.interfaceName.c_str(),
        .processName = this->statsData_.processName.c_str(),
        .ddkVersion = nullptr,
        .result = result,
        .runTime = this->statsData_.runTime,
        .callTime = this->statsData_.callTime
    };
    g_requestStatsFunc(statsInfo);
}
// 打点函数为一次性行为，处理时间基本为零，使用此函数进行打点
void AiStatsLogBuilder::Stats(unsigned int uid, AiStatsEngineType engineType, const char* clientInterfaceName,
    const char* processName, int result)
{
    if (Init() != SUCCESS) {
        return;
    }
    HIAI_EXPECT_NOT_NULL_VOID(g_requestStatsFunc);
    this->CallTimeNow();
    HIAI_Stats_Info statsInfo {
        .uid = uid,
        .engineType = engineType,
        .interfaceName = clientInterfaceName,
        .processName = processName,
        .ddkVersion = nullptr,
        .result = result,
        .runTime = 0,
        .callTime = this->statsData_.callTime
    };
    g_requestStatsFunc(statsInfo);
}

void AiStatsLogBuilder::Stats(unsigned int uid, AiStatsEngineType engineType, const char* clientInterfaceName,
    const char* processName, const char* ddkVersion, int result)
{
    if (Init() != SUCCESS) {
        return;
    }
    HIAI_EXPECT_NOT_NULL_VOID(g_requestStatsFunc);
    this->CallTimeNow();
    HIAI_Stats_Info statsInfo {
        .uid = uid,
        .engineType = engineType,
        .interfaceName = clientInterfaceName,
        .processName = processName,
        .ddkVersion = ddkVersion,
        .result = result,
        .runTime = 0,
        .callTime = this->statsData_.callTime
    };
    g_requestStatsFunc(statsInfo);
}
}  // namespace stats
